home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / x / volume5 / xnetload / part01 next >
Encoding:
Text File  |  1989-10-09  |  27.9 KB  |  948 lines

  1. Path: uunet!island!argv
  2. From: argv@island.uu.net (Dan Heller)
  3. Newsgroups: comp.sources.x
  4. Subject: v05i009: New xnetload - version 1.5, Part01/01
  5. Message-ID: <1114@island.uu.net>
  6. Date: 9 Oct 89 21:37:06 GMT
  7. Organization: Island Graphics, Marin County, California
  8. Lines: 937
  9. Approved: island!argv@sun.com
  10.  
  11. Submitted-by: "J. Michael Berkley" <jmberkley@watnext.waterloo.edu>
  12. Posting-number: Volume 5, Issue 9
  13. Archive-name: xnetload/part01
  14.  
  15. [ this is not a patch; this is a new version --argv ]
  16.  
  17. The following shar file is the newest xnetload - a multiple xload
  18. using rwhod stats.
  19. ------------------------------------------------------------------------
  20. # This is a shell archive.  Remove anything before this line,
  21. # then unpack it by saving it in a file and typing "sh file".
  22. #
  23. # Wrapped by watnext!jmberkley on Wed Oct  4 10:09:27 EDT 1989
  24. # Contents:  xnetload/README xnetload/Imakefile xnetload/xnetload.c
  25. #    xnetload/getload.c xnetload/xnetload.1 xnetload/Makefile
  26. #    xnetload/AUTHOR xnetload/patchlevel.h
  27.  
  28. if test ! -d xnetload ; then
  29.     mkdir xnetload
  30. fi
  31.  
  32. echo x - xnetload/README
  33. sed 's/^@//' > "xnetload/README" <<'@//E*O*F xnetload/README//'
  34. README for xnetload
  35. Mike Berkley, September 1989
  36.  
  37. xnetload gives the system load for a list of remote machines by using
  38. rwhod statistics.  The load for the local machine is also displayed,
  39. but is calculated using the standard Load widget routines, (this means
  40. that xnetload needs to be setgid kmem.)
  41.  
  42. There's an option to turn off the local load, -nolocal, which would
  43. allow you to run with xnetload non-setgid.  Alternatively, you can
  44. compile xnetload with -DNOLOCAL (see the Imakefile and Makefile).
  45.  
  46. xnetload was developed on a uVax running Ultrix.  It also compiles and
  47. runs on Sun (both SunOS 3.5 and 4), MIPS and Sequent.  Of course,
  48. there are some little glitches: the Makefile needs to be altered and
  49. you may need to find memcpy() somewhere.
  50.  
  51. xnetload was written mostly as a tool to learning how to use the
  52. toolkit.  I was amazed at what the toolkit can do in not very many
  53. lines of code.
  54.  
  55. Since this was an experiment/learning tool, I'm sure that I did not
  56. follow all of the correct X guidelines, but I tried.
  57.  
  58. The getload() routine is just my own kludge to read rwhod stats.  It
  59. works, but it is replaceable.  Ideally, I would like to use some kind
  60. of system call like Sun 4's RPC versions of rwho and rup command, then
  61. there would not be any dependency on rwhod.  If you are living on a
  62. system that does not use rwhod, or you would like a more efficient way
  63. of determining system load, then you can replace getload() without
  64. breaking the rest of the program.
  65.  
  66. ** Note - if you define "*Load*update", but not  **
  67. ** "xnetload*remote*update", then xnetload will  **
  68. ** set both the remote and local update times to **
  69. ** the "*Load*update" value.  If this time is    **
  70. ** much less than the rwhod update period, then  **
  71. ** the remote load displays will look more like  **
  72. ** bar graphs.                                   **
  73.  
  74. Send comments, bug reports, etc. to jmberkley@watnext.waterloo.edu.
  75.  
  76.  Mike Berkley, University of Waterloo
  77.  PAMI Lab
  78.  jmberkley@watnext.waterloo.edu
  79.  {utai,uunet}!watmath!watnext!jmberkley
  80. @//E*O*F xnetload/README//
  81. chmod u=rw,g=r,o=r xnetload/README
  82.  
  83. echo x - xnetload/Imakefile
  84. sed 's/^@//' > "xnetload/Imakefile" <<'@//E*O*F xnetload/Imakefile//'
  85. #
  86. # Imakefile for xnetload
  87. #
  88. # Written by: Mike Berkley, jmberkley@watnext.waterloo.edu, 1989
  89. #
  90. # Permission to use, copy, modify and distribute (without charge) this
  91. # software and its documentation is granted, provided that this comment
  92. # is retained.
  93.  
  94. #
  95. # Since xnetload finds the local machine's load using the standard Load
  96. # widget stuff, it needs to be able to read kmem, i.e.  setgid kmem.  If
  97. # you do not want this, then define NOLOCAL
  98. #        DEFINES = -O -DNOLOCAL
  99.  
  100.        INCLUDES = -I$(TOP) -I$(TOP)/X11
  101.  
  102. # Dynix doesn't have -L option on load, but I have left changing the
  103. # XLIB specification up to individual sites.  Dynix and our Sun 3.5
  104. # don't come with a memcpy, so you'll have to add in whichever library
  105. # has memcpy.
  106. /* LOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB) */
  107. LOCAL_LIBRARIES = -L/usr/software/X11/lib -lXaw -lXmu -lXt -lX11
  108.  
  109.            SRCS = xnetload.c getload.o
  110.            OBJS = xnetload.o getload.o
  111.  
  112.    INSTALLFLAGS = $(INSTKMEMFLAGS)
  113.  
  114. all: xnetload
  115.  
  116. SingleProgramTarget(xnetload,$(OBJS),,$(LOCAL_LIBRARIES))
  117. @//E*O*F xnetload/Imakefile//
  118. chmod u=rw,g=r,o=r xnetload/Imakefile
  119.  
  120. echo x - xnetload/xnetload.c
  121. sed 's/^@//' > "xnetload/xnetload.c" <<'@//E*O*F xnetload/xnetload.c//'
  122. /* 
  123.  * xnetload.c: multiple xload, using rwho statistics
  124.  * $Date: 89/10/04 10:04:41 $ $Revision: 1.5 $
  125.  *
  126.  * Copyright 1989 University of Waterloo
  127.  *
  128.  * Permission to use, copy, modify, and distribute this software and its
  129.  * documentation for any purpose and without fee is hereby granted, provided
  130.  * that the above copyright notice appear in all copies and that both that
  131.  * copyright notice and this permission notice appear in supporting
  132.  * documentation, and that the name of UW not be used in advertising
  133.  * or publicity pertaining to distribution of the software without specific,
  134.  * written prior permission.  UW makes no representations about the
  135.  * suitability of this software for any purpose.  It is provided "as is"
  136.  * without express or implied warranty.
  137.  *
  138.  * UW DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  139.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL UW
  140.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  141.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  142.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  143.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  144.  *
  145.  * Author:  Mike Berkley, jmberkley@watnext.waterloo.edu, 1989
  146.  *
  147.  */
  148.  
  149. /*
  150.  * xnetload uses the Load widget load proc to get the local
  151.  * machine load.  This means that xnetload needs to be setgid
  152.  * kmem.  If you do not want this, then define NOLOCAL when compiling.
  153.  */
  154.  
  155. #include <stdio.h>
  156. #include <netdb.h>
  157. #include <ctype.h>
  158. #include <X11/Xos.h>
  159. #include <X11/Intrinsic.h>
  160. #include <X11/StringDefs.h>
  161. #include <X11/Shell.h>
  162. #include <X11/Form.h>
  163. #include <X11/Load.h>
  164. #include "patchlevel.h"
  165.  
  166. void GetStatus();
  167. extern int getload();         /* gets rwho load */
  168. extern char *malloc();
  169. extern char *strtok();
  170. static Widget makestatuswidget(), makeremotestatus(), makesubform();
  171. static void modifyloadcall();
  172. static void SetRemUpdate();
  173.  
  174. #define DOWNMSG      " DOWN"
  175. #define DEFREMUPDATE (60)    /* remote update defaults to 60 seconds */
  176. #define BIGNUM (99999)        /* ~infinite number of load widgets */
  177.  
  178. /* arguments to Form widget */
  179. static Arg Formargs[] = {
  180.     { XtNfromVert, (XtArgVal) NULL },       /* Chain from .value wid */
  181.     { XtNdefaultDistance, (XtArgVal) 1 },   /* default spacing */
  182.     { XtNresizable, (XtArgVal) TRUE },      /* allow resize */
  183. };
  184.  
  185. /* Arguments to load windows */
  186. static Arg Statusargs[] = {
  187.     { XtNfromHoriz, (XtArgVal) NULL },      /* Chain from .value wid */
  188.     { XtNresizable, (XtArgVal) TRUE },      /* allow resize */
  189.     { XtNborderWidth, (XtArgVal) 0 },       /* 0 border for load wid  */
  190.     { XtNlabel, (XtArgVal) NULL },          /* Load title */
  191. };
  192.  
  193. /* Application specific resources - turn off local load display */
  194. static String Configuration;
  195. static Boolean Localload;
  196. static XtResource app_resources[] = {
  197.     { "localload", "LocalLoad", XtRBoolean, sizeof(Boolean),
  198.     (Cardinal) &Localload, XtRString,
  199. /* if NOLOCAL is defined, then no local is displayed, by default */
  200. #ifdef NOLOCAL
  201. "off"
  202. #else
  203. "on"
  204. #endif
  205. },
  206.   /* configuration of loads - horizontal, vertical or mXn/mxn */
  207.   { "configuration", "Configuration", XtRString, sizeof(String),
  208.       (Cardinal) &Configuration, XtRString, "horizontal" },
  209. };
  210.  
  211. /* command line options for local load display and configuration */
  212. /* If compiled NOLOCAL, then off is default, but on still allowed */
  213. static XrmOptionDescRec app_options[] = {
  214.     { "-local", "localload", XrmoptionNoArg, "on" },
  215.     { "-nolocal", "localload", XrmoptionNoArg, "off" },
  216.     { "-configuration", "configuration", XrmoptionSepArg, "vertical"},
  217. };
  218.  
  219. main(argc,argv)
  220. int argc;
  221. char *argv[];
  222. {
  223.     int currarg;             /* arg counter to walk through hosts */
  224.     int maincount,subcount,count;
  225.     String maindirection,subdirection;
  226.     static Widget toplevel, mainform, subform, statuswin, head;
  227.  
  228.     /* The toolkit tries to open your display if you use -help */
  229.     /* so let's do it the other way */
  230.     if((argc > 1) && !strncmp(argv[1],"-help",5)) {
  231.         usage();
  232.         exit(0);
  233.     }
  234.  
  235.     /* Initialize the top level */
  236.     toplevel = XtInitialize(*argv[0], "XNetload",
  237.                             app_options, XtNumber(app_options), &argc, argv);
  238.  
  239.     /* Set remote load update to default to DEFREMUPDATE seconds */
  240.     SetRemUpdate(toplevel);
  241.  
  242.     /* Get local vs nolocal, configuration */
  243.     XtGetApplicationResources( toplevel, (caddr_t)NULL,
  244.                   app_resources, XtNumber(app_resources),
  245.                   NULL, (Cardinal) 0);
  246.       
  247.     /* Parse configuration */
  248.     if(strncmp(Configuration,"horiz",5) == 0) {
  249.     subcount = BIGNUM;    /* ~ inf num of widgets horizontally */
  250.     maincount = 1;
  251.     }
  252.     else if(strncmp(Configuration,"vert",4) == 0) {
  253.     maincount = BIGNUM;    /* ~ inf num of widgets horizontally */
  254.     subcount = 1;
  255.     }
  256.     else {
  257.     /* format is 4x5 for 4 columns, 5 rows */
  258.     strtok(Configuration,"xX");
  259.     if(Configuration[0] == '*')
  260.       subcount = BIGNUM;
  261.     else if(! isdigit(Configuration[0])) {
  262.         usage();
  263.         exit(-1);
  264.     }
  265.     else if((subcount = atoi(Configuration)) == 0)
  266.       subcount = 1;
  267.     
  268.     Configuration = strtok((char *)NULL,"xX");
  269.     if(Configuration[0] == '*')
  270.       maincount = BIGNUM;
  271.     else if(! isdigit(Configuration[0])) {
  272.         usage();
  273.         exit(-1);
  274.     }
  275.     else if((maincount = atoi(Configuration)) == 0)
  276.       maincount = 1;
  277.     }
  278.  
  279.     if(subcount >= maincount) {
  280.     maindirection = XtNfromVert;
  281.     subdirection = XtNfromHoriz;
  282.     }
  283.     /* need to swap so that bigger count is the sub count */
  284.     /* This lowers the number of form widgets */
  285.     else {
  286.     maindirection = XtNfromHoriz;
  287.     subdirection = XtNfromVert;
  288.     /* swap counts */
  289.     count = subcount;subcount = maincount;maincount = count;
  290.     }
  291.     /* adjust subcount so that we don't always get one row if we use Nx* */
  292.     if(subcount == BIGNUM) {
  293.     subcount = argc/maincount;
  294.     if(maincount * subcount != argc)
  295.       subcount++;
  296.     }
  297.  
  298.     /* Create a Form widget to contain all of the Loads */
  299.     mainform =
  300.       XtCreateManagedWidget("outerform",
  301.                             formWidgetClass,
  302.                             toplevel,
  303.                             Formargs,
  304.                             XtNumber(Formargs));
  305.  
  306.     /* Make the first sub-form widget, to contain one row/col */
  307.     subform = makesubform(mainform,NULL,maindirection);
  308.  
  309.     /*
  310.      * load widget reads kmem for local load.  Define NOLOCAL if you
  311.      * don't want this.
  312.      */
  313.     count = 0;
  314.     if(Localload) {
  315.         /* Get and set label name */
  316.         String labelname = malloc(BUFSIZ*sizeof(char));
  317.         gethostname(labelname,BUFSIZ);
  318.     strtok(labelname,".");
  319.  
  320.         /* Create the local load widget */
  321.         statuswin =
  322.       makestatuswidget(labelname,subform,(Widget)NULL,
  323.                "local",subdirection);
  324.     count++;        /* So local added into subform count */
  325.     }
  326.  
  327.     /* Remote Loads */
  328.     /* currarg initialized above */
  329.     for(currarg = 1;(currarg < argc)&&(maincount > 0);maincount--) {
  330.     for(;(currarg < argc)&&(count < subcount);count++,currarg++) {
  331.         if(count > 0) {
  332.         /* Chain to first load */
  333.         statuswin = makeremotestatus(argv[currarg],
  334.                          subform,
  335.                          statuswin,
  336.                          subdirection);
  337.         }
  338.         else {
  339.         /* chain to left/top edge of subform */
  340.         statuswin = makeremotestatus(argv[currarg],
  341.                          subform,
  342.                          NULL,
  343.                          subdirection);
  344.         }
  345.     }
  346.     count = 0;
  347.     /* make another subform if there are more machines */
  348.     if((currarg < argc) && (maincount > 1))
  349.       subform = makesubform(mainform,subform,maindirection);
  350.     }
  351.  
  352.     /* if there are no loads to display, then should stop   */
  353.     /* Note, statuswin is static, guaranteed to start at 0, */
  354.     /* so it's non-zero only if a load widget was created   */
  355.     if(!statuswin) {
  356.         fprintf(stderr,"xnetload: No machines to display\n");
  357.         usage();
  358.         exit(0);
  359.     }
  360.  
  361.     /* draw the widgets, and look for new events */
  362.     XtRealizeWidget(toplevel);
  363.     XtMainLoop();
  364. }
  365.  
  366. /*
  367.  * Make a sub form widget
  368.  */
  369. static Widget
  370. makesubform(formwin,lastwin,direction)
  371. Widget formwin,lastwin;
  372. String direction;
  373. {
  374.     /* set up chain to previous widget */
  375.     XtSetArg(Formargs[0],direction, (XtArgVal)lastwin);
  376.  
  377.     /* Create the local form */
  378.     return(XtCreateManagedWidget("subform",
  379.                  formWidgetClass,
  380.                  formwin,
  381.                  Formargs,
  382.                  XtNumber(Formargs)));
  383. }
  384.  
  385. /*
  386.  * Make a status widget
  387.  */
  388. static Widget
  389. makestatuswidget(label,formwin,lastwin,name,direction)
  390. char *label;
  391. Widget formwin,lastwin;
  392. String name,direction;
  393. {
  394.     XtSetArg(Statusargs[XtNumber(Statusargs)-1],
  395.          XtNlabel,(XtArgVal)label);
  396.     /* set up chain to previous Load widget */
  397.     XtSetArg(Statusargs[0],direction,(XtArgVal)lastwin);
  398.     
  399.     /* Create the load widget */
  400.     return(XtCreateManagedWidget(name,
  401.                  loadWidgetClass,
  402.                  formwin,
  403.                  Statusargs,
  404.                  XtNumber(Statusargs)));
  405. }
  406.  
  407. /*
  408.  * Make a remote status widget
  409.  */
  410. static Widget
  411. makeremotestatus(hostname,formwin,lastwin,direction)
  412. String hostname;
  413. Widget formwin,lastwin;
  414. String direction;
  415. {
  416.     String labelname;        /* label, could be "machine DOWN" */
  417.     struct hostent *host;    /* for gethostbyname() */
  418.     Widget remotestatus;
  419.  
  420.     /* translate command arg to a hostname */
  421.     host = gethostbyname(hostname);
  422.     /* if host == NULL, then hostname is junk for some reason */
  423.     if(!host) 
  424.       return(NULL);
  425.  
  426.     /* get rid of domain's in fully specified host names */
  427.     strtok(host->h_name,".");
  428.     /* allocate memory for name and downmsg for label */
  429.     if(!(labelname=malloc((strlen(host->h_name)
  430.                +strlen(DOWNMSG)+1)*sizeof(char))
  431.      )) {
  432.     perror("xnetload: Ran out of memory for labelname");
  433.     exit(1);
  434.     }
  435.     /* set label name */
  436.     strcpy(labelname,host->h_name);
  437.     remotestatus = makestatuswidget(labelname,formwin,lastwin,
  438.                     "remote",direction);
  439.  
  440.     modifyloadcall(remotestatus,host->h_name);
  441.     return(remotestatus);
  442. }
  443.     
  444.  
  445. /*
  446.  * replace standard load widget status call with one that looks at rwho
  447.  */
  448. static void
  449. modifyloadcall(statuswin,name)
  450. Widget statuswin;
  451. String name;
  452. {
  453.     String hostname;
  454.  
  455.     /* allocate memory for hostname */
  456.     if(!(hostname=
  457.      malloc((strlen(name)+1)*sizeof(char)))) {
  458.     perror("xnetload: Ran out of memory for name");
  459.     exit(1);
  460.     }
  461.     /* Set up hostname, and load callback (GetStatus()) */
  462.     strcpy(hostname,name);
  463.     XtRemoveAllCallbacks(statuswin, XtNgetLoadProc);
  464.     XtAddCallback(statuswin,XtNgetLoadProc,
  465.           GetStatus,(caddr_t)hostname);
  466. }
  467.  
  468. /*
  469.  * You're wondering why I'm doing this, right?  Well, the default update
  470.  * for the Load widget is 5 seconds (I think), but if rwhod updates the
  471.  * files every 60 seconds, then the load displays will look weird.  So, I
  472.  * don't force the user to have a 60 second update, but I at least make
  473.  * this the default.
  474.  */
  475. static void
  476. SetRemUpdate(w)
  477. Widget w;
  478. {
  479.     XrmDatabase rdb;
  480.     char resourceline[50];
  481.  
  482.     /* Make a database with new default */
  483.     sprintf(resourceline,"%s: %d\n","xnetload*remote*update",DEFREMUPDATE);
  484.     rdb = XrmGetStringDatabase(resourceline);
  485.  
  486.     /* merge existing Display database into new one */
  487.     /* so that user choices are preserved */
  488.     XrmMergeDatabases(XtDisplay(w)->db,&rdb);
  489.  
  490.     /* Set Display database to new one */
  491.     XtDisplay(w)->db = rdb;
  492. }
  493.  
  494. /* GetStatus() global vars */
  495. static char *Label;
  496. static Arg Labelarg[1];
  497. /*
  498.  * Load callback function
  499.  *    - calls getload to determine current load, then updates labels
  500.  */
  501. void
  502. GetStatus(w,closure,call_data)
  503. Widget w;                        /* load widget */
  504. caddr_t closure;                 /* name of host, char*  */
  505. caddr_t call_data;               /* load, float*  */
  506. {
  507.     int load;                    /* current load for this machine */
  508.  
  509.     /* get current label for widget */
  510.     XtSetArg(Labelarg[0],XtNlabel,(XtArgVal)&Label);
  511.     XtGetValues(w,Labelarg,(Cardinal)1);
  512.  
  513.     /* if load is less than zero, then machine is down or something */
  514.     if((load = getload(closure)) < 0) {
  515.         *(double *)call_data = 0.0;
  516.         /* update label with DOWN message */
  517.         if(!matchstr(Label,DOWNMSG)) {
  518.         updatelabel(w,(char *)closure,DOWNMSG);
  519.     }
  520.     }
  521.     /* otherwise we found a good load, so use it */
  522.     else {
  523.         *(double *)call_data = (double)load/100.0;
  524.         /* hate to do this everytime, but we have to check */
  525.         if(matchstr(Label,DOWNMSG)) {
  526.         updatelabel(w,(char *)closure,"");
  527.     }
  528.         return;
  529.     }
  530. }
  531.  
  532. /*
  533.  * look for pat in str - exact match, no wild cards here
  534.  */
  535. static int
  536. matchstr(str,pat)
  537. register char *str, *pat;
  538. {
  539.     while(str = index(str,*pat))
  540.       if(! strcmp(str++,pat))
  541.         return(TRUE);
  542.     return(FALSE);
  543. }
  544.  
  545. /*
  546.  * replace label with str and msg
  547.  */
  548. static int
  549. updatelabel(w,str,msg)
  550. Widget w;
  551. register char *str, *msg;
  552. {
  553.     XEvent Sendevent;
  554.  
  555.     sprintf(Label,"%s%s",str,msg);
  556.     XtSetArg(Labelarg[0],XtNlabel, (XtArgVal)Label);
  557.     XtSetValues(w,Labelarg, (Cardinal)1);
  558.  
  559.     /* Load widget doesn't redraw when label is changed.  Force it! */
  560.     XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,TRUE);
  561. }
  562.  
  563. static int
  564. usage()
  565. {
  566.     fprintf(stderr,"usage:\n xnetload [-configuration mXn] [-nolocal] [machine] ...\n");
  567. }
  568. @//E*O*F xnetload/xnetload.c//
  569. chmod u=rw,g=r,o=r xnetload/xnetload.c
  570.  
  571. echo x - xnetload/getload.c
  572. sed 's/^@//' > "xnetload/getload.c" <<'@//E*O*F xnetload/getload.c//'
  573. /* 
  574.  * getload.c: get load, using rwho statistics - used in xnetload
  575.  *
  576.  * Copyright 1989 University of Waterloo
  577.  *
  578.  * Permission to use, copy, modify, and distribute this software and its
  579.  * documentation for any purpose and without fee is hereby granted, provided
  580.  * that the above copyright notice appear in all copies and that both that
  581.  * copyright notice and this permission notice appear in supporting
  582.  * documentation, and that the name of UW not be used in advertising
  583.  * or publicity pertaining to distribution of the software without specific,
  584.  * written prior permission.  UW makes no representations about the
  585.  * suitability of this software for any purpose.  It is provided "as is"
  586.  * without express or implied warranty.
  587.  *
  588.  * UW DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  589.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL UW
  590.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  591.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  592.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  593.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  594.  *
  595.  * Author:  Mike Berkley, jmberkley@watnext.waterloo.edu, 1989
  596.  *
  597.  */
  598.  
  599. /* getload includes - no need for X stuff */
  600. #include <stdio.h>
  601. #include <ctype.h>
  602. #include <netdb.h>
  603. #include <sys/file.h>
  604. #include <sys/types.h>
  605. #include <sys/time.h>
  606.  
  607. /* Dynix doesn't have an rwhod.h file, so here's the struct for that system */
  608. #ifdef sequent
  609. struct  outmp {
  610.     char  out_line[8];    /* tty name */
  611.     char  out_name[8];    /* user id */
  612.     long  out_time;       /* time on */
  613. };
  614. struct  whod {
  615.     char  wd_vers;
  616.     char  wd_type;
  617.     char  wd_fill[2];
  618.     int   wd_sendtime;
  619.     int   wd_recvtime;
  620.     char  wd_hostname[32];
  621.     int   wd_loadav[3];
  622.     int   wd_boottime;
  623.     struct whoent {
  624.         struct outmp    we_utmp;
  625.         int             we_idle;
  626.     } wd_we[1024 / sizeof (struct whoent)];
  627. };
  628. #else
  629. #include <protocols/rwhod.h>
  630. #endif
  631.  
  632. extern time_t time();
  633.  
  634. #define DOWNTIME (60 * 5)
  635. #define ISDOWN(now,wd) (((now) - (wd).wd_recvtime) > DOWNTIME)
  636. #define RWHODHD "/usr/spool/rwho/whod"
  637.  
  638. /*
  639.  * actual function to get the load
  640.  * reads rwhod stats to find the load average of a machine
  641.  */
  642. int
  643. getload(hostname)
  644. char *hostname;
  645. {
  646.     int nbytes;            /* number of bytes read */
  647.     int fd;            /* file descriptor */
  648.     int counter;        /* loop counter */
  649.     time_t currtime;        /* current time */
  650.     struct whod    wd;
  651.     char buf[sizeof(struct whod)], fname[256];
  652.  
  653.     sprintf(fname,"%s.%s",RWHODHD,(char *)hostname);
  654.  
  655.     (void) time(&currtime);
  656.  
  657.     /* Loop 3 times, looking for a non-zero load. */
  658.     /* This keeps us from getting a zero load if rwhod is in */
  659.     /* the process of doing something to the file.  This is */
  660.     /* important, since we'll get strange looking zero gaps */
  661.     /* in the graph if we don't try our best to get a non-zero load. */
  662.     for(counter=0;counter<=3;counter++) {
  663.         /* open and read from the file */
  664.         if((fd = open(fname, O_RDONLY, 0)) < 0)
  665.           /* we can't open file, so it's down or something */
  666.           return(-1);
  667.  
  668.         nbytes = read(fd, buf, sizeof(struct whod));
  669.         close(fd);
  670.         /* if we got enough bytes, then copy it to wd */
  671.         if(nbytes >= (sizeof (wd) - sizeof(wd.wd_we))) {
  672.  
  673.             /* NOT everbody has memcpy, but can't use strncpy() */
  674.             memcpy(&wd,buf,(sizeof (wd) - sizeof(wd.wd_we)));
  675.  
  676.             /* ISDOWN macro, if machine is really down or faking */
  677.             if(ISDOWN(currtime,wd))
  678.               return(-1);
  679.             else if(wd.wd_loadav[0] > 0)
  680.               return(wd.wd_loadav[0]);
  681.         }
  682.  
  683.         /* If we got to here, then we need to loop again */
  684.         sleep(1);
  685.     }
  686.     return(0);        /* couldn't read load if here */
  687. }
  688. @//E*O*F xnetload/getload.c//
  689. chmod u=rw,g=r,o=r xnetload/getload.c
  690.  
  691. echo x - xnetload/xnetload.1
  692. sed 's/^@//' > "xnetload/xnetload.1" <<'@//E*O*F xnetload/xnetload.1//'
  693. @.TH XNETLOAD l "April 1989" "X Version 11"
  694. @.SH NAME
  695. xnetload - display load averages from local network machines
  696. @.SH SYNOPSIS
  697. @.B xnetload
  698. @.br
  699. [
  700. @.B \-configuration
  701. (<column>x<row>|horizontal|vertical)
  702. ]
  703. @.br
  704. [
  705. @.B \-nolocal
  706. ]
  707. @.br
  708. [
  709. machine
  710. ] ...
  711. @.SH DESCRIPTION
  712. @.I xnetload 
  713. uses the Athena Load widget and
  714. @.B rwhod
  715. statistics to display the
  716. load average of a number of machines on a local network.
  717. @.SH OPTIONS
  718. @.PP
  719. @.I xnetload
  720. accepts all of the standard X Toolkit command line options along with the 
  721. following additional options:
  722. @.PP
  723. @.TP 8
  724. @.B \-configuration <column>x<row>
  725. @.I xnetload
  726. can be configured to show the machine loads horizontally, vertically,
  727. or in multiple columns and rows:
  728.  
  729. @.br
  730. \fI-configuration horizontal\fR - display machine loads in one row
  731.  
  732. @.br
  733. \fI-configuration vertical\fR - display machine loads in one column
  734.  
  735. @.br
  736. \fI-configuration 4x3\fR - display machine loads in four columns,
  737. three columns (maximum of 12 machines).
  738.  
  739. @.br
  740. \fI-configuration 2x*\fR - display machine loads in two columns, no
  741. maximum number of machines, but an odd number will result in one blank
  742. entry.
  743.  
  744. @.br
  745. \fI-configuration *x3\fR - display machine loads in three rows, no
  746. maximum number of machines, but a number not divisible by three will
  747. result in blank entries.
  748.  
  749. @.PP
  750. @.TP 8
  751. @.B \-nolocal
  752. By default, the load for the local machine is displayed and the
  753. load calculated using the
  754. Load widget's standard LoadProc.  With this option,
  755. @.I xnetload
  756. will NOT display
  757. the local machine's load unless the hostname is listed
  758. on the command line.  When
  759. @.B \-nolocal
  760. is used,
  761. @.I xnetload
  762. will not try to read
  763. @.I kmem.
  764. @.PP
  765. @.TP 8
  766. @.B \-local
  767. If
  768. @.I xnetload
  769. is compiled with
  770. @.B \-DNOLOCAL,
  771. then no local load will
  772. be displayed by default.
  773. @.B \-local
  774. will turn the local load back on, and make
  775. @.I xnetload
  776. read
  777. @.I kmem.
  778. @.PP
  779. @.TP 8
  780. @.B [machine] ...
  781. The load for each machine listed will be displayed.
  782. @.SH RESOURCES
  783. @.I xnetload
  784. uses the standard toolkit resources and some private resources.
  785. These are some of the standard resources that
  786. I find useful:
  787. @.br
  788. @.sp
  789. !**** XLOAD ****
  790. @.br
  791. *Load*font:                          6x10
  792. @.br
  793. *Load*height:                        35
  794. @.br
  795. *Load*width:                         90
  796. @.br
  797. !**** XMULTIMETER ****
  798. @.br
  799. xnetload.geometry:                   -0+0
  800. @.br
  801. ! number of seconds between updates for local machine
  802. @.br
  803. xnetload*local*update:               15
  804. @.br
  805. ! number of seconds between updates for remote machines
  806. @.br
  807. xnetload*remote*update:              60
  808. @.sp
  809. @.PP
  810. Note - if you define "*Load*update", but not "xnetload*remote*update",
  811. then
  812. @.I xnetload
  813. will set both the remote and local update times to the "*Load*update"
  814. value.  If this time is much less than the
  815. @.B rwhod
  816. update period, (eg. 5 seconds instead of 60 seconds)
  817. then the remote load displays will look like bar graphs.
  818. @.PP
  819. The private
  820. @.I xnetload
  821. resources are as follows:
  822. @.sp
  823. @.IP "\fBconfiguration\fP (string) ``horizontal''"
  824. Gives the configuration of the load widgets - use the same syntax as with
  825. the command line argument: \fIhorizontal\fP for one row \fIvertical\fP
  826. for one column, \fImxn\fP or \fImXn\fP for m columns and n rows,
  827. \fImx*\fP for m columns and the rows necessary, and \fI*xn\fP for n
  828. rows with the necessary number of columns.
  829. @.IP "\fBlocalload\fP (boolean) ``on''"
  830. If
  831. @.I localload
  832. is true, then
  833. @.I xnetload
  834. will use the standard Load widget load function to get the load
  835. average for the local machine.  There is a compile time switch to make
  836. this default "off."
  837. @.SH SEE ALSO
  838. X(1), xload(1), Athena Load widget
  839. @.SH BUGS
  840. @.I xnetload
  841. uses the Load widget's normal load function for the local
  842. system, therefore
  843. @.I xnetload
  844. should be setgid
  845. @.I kmem.
  846. If
  847. @.I xnetload
  848. cannot be setgid
  849. @.I kmem,
  850. then either compile with
  851. @.B \-DNOLOCAL
  852. or use the
  853. @.B \-nolocal
  854. option.
  855. @.PP
  856. @.I xnetload
  857. will also take a width and height on the application
  858. geometry specification, but sometimes the
  859. @.I Form
  860. widget will leave small gaps between the loads.
  861. @.PP
  862. A very wide
  863. @.I xnetload
  864. will often have wide margins.  I think the
  865. @.I Form
  866. widget is doing this.
  867. @.SH AUTHOR
  868. J. Michael Berkley
  869. (jmberkley@watnext.waterloo.edu)
  870. @//E*O*F xnetload/xnetload.1//
  871. chmod u=rw,g=r,o=r xnetload/xnetload.1
  872.  
  873. echo x - xnetload/Makefile
  874. sed 's/^@//' > "xnetload/Makefile" <<'@//E*O*F xnetload/Makefile//'
  875. #
  876. # Makefile for xnetload
  877. #
  878. # Written by: Mike Berkley, jmberkley@watnext.waterloo.edu, 1989
  879. #
  880. # Permission to use, copy, modify and distribute (without charge) this
  881. # software and its documentation is granted, provided that this comment
  882. # is retained.
  883. #
  884.  
  885. # Since xnetload finds the local machine's load using the standard Load
  886. # widget stuff, it needs to be able to read kmem, i.e.  setgid kmem.  If
  887. # you do not want this, then define NOLOCAL
  888. # CFLAGS = -O -DNOLOCAL
  889. # CC=gcc -traditional
  890. CFLAGS = -O
  891.  
  892. XINC = /software/X11/include
  893. XLIB = /software/X11/lib
  894.  
  895. # Dynix doesn't have -L option on load, but I have left changing the
  896. # XLIB specification up to individual sites.  Dynix and our Sun 3.5
  897. # don't come with a memcpy, so you'll have to add in whichever library
  898. # has memcpy.
  899.  
  900. INCLUDES = -I$(XINC)
  901. LIBS = -L$(XLIB) -lXaw -lXmu -lXt -lX11
  902. OBJS = xnetload.o getload.o
  903.  
  904. xnetload: $(OBJS)
  905.     $(CC) $(CFLAGS) -o xnetload $(OBJS) $(LIBS)
  906.  
  907. @.c.o:
  908.     $(CC) $(CFLAGS) -c $(INCLUDES) $<
  909. @//E*O*F xnetload/Makefile//
  910. chmod u=rw,g=r,o=r xnetload/Makefile
  911.  
  912. echo x - xnetload/AUTHOR
  913. sed 's/^@//' > "xnetload/AUTHOR" <<'@//E*O*F xnetload/AUTHOR//'
  914. xnetload was written by Mike Berkley, jmberkley@watnext.waterloo.edu
  915.  
  916. Permission to use, copy, modify and distribute (without charge) this
  917. software and its documentation is granted, provided that this comment
  918. is retained.
  919. @//E*O*F xnetload/AUTHOR//
  920. chmod u=rw,g=r,o=r xnetload/AUTHOR
  921.  
  922. echo x - xnetload/patchlevel.h
  923. sed 's/^@//' > "xnetload/patchlevel.h" <<'@//E*O*F xnetload/patchlevel.h//'
  924. #define PATCHLEVEL 0
  925. @//E*O*F xnetload/patchlevel.h//
  926. chmod u=rw,g=r,o=r xnetload/patchlevel.h
  927.  
  928. echo Inspecting for damage in transit...
  929. temp=/tmp/shar$$; dtemp=/tmp/.shar$$
  930. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  931. cat > $temp <<\!!!
  932.       46     336    2026 README
  933.       32     157    1060 Imakefile
  934.      446    1637   13099 xnetload.c
  935.      115     559    3843 getload.c
  936.      177     652    4086 xnetload.1
  937.       34     164     977 Makefile
  938.        5      29     222 AUTHOR
  939.        1       3      21 patchlevel.h
  940.      856    3537   25334 total
  941. !!!
  942. wc  xnetload/README xnetload/Imakefile xnetload/xnetload.c xnetload/getload.c xnetload/xnetload.1 xnetload/Makefile xnetload/AUTHOR xnetload/patchlevel.h | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  943. if [ -s $dtemp ]
  944. then echo "Ouch [diff of wc output]:" ; cat $dtemp
  945. else echo "No problems found."
  946. fi
  947. exit 0
  948.